package com.softdev.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.softdev.common.CustomException;
import com.softdev.common.mapper.ProjectDtoMapper;
import com.softdev.common.mapper.ProjectMapper;
import com.softdev.dto.ProjectDto;
import com.softdev.dto.ProjectResultDto;
import com.softdev.dto.RiskDto;
import com.softdev.pojo.*;
import com.softdev.repo.*;
import com.softdev.service.ProjectService;
import com.softdev.utils.DataUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ProjectServiceImpl implements ProjectService {

    @Resource
    private ProjectRepository projectRepository;

    @Resource
    private UserRepository userRepository;

    @Resource
    private SkillRepository skillRepository;

    @Resource
    private RiskRepository riskRepository;

    @Resource
    private ProjectRiskMappingRepository mappingRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(ProjectDto projectDto) {

        Project project = ProjectDtoMapper.INSTANCE.projectDtoToProject(projectDto);

        List<Skill> skills = skillRepository.findAllById(Arrays.asList(projectDto.getSkillIds()));
        project.setStatus(0);
        project.setCur(0);
        project.setSkills(skills);

        Set<Module> modules = projectDto.getModuleDtos().stream().map(moduleDto -> {

            Module module = new Module();

            List<User> users = Arrays.stream(moduleDto.getUserIds())
                    .map(userId -> userRepository.findByIdWithRoles(userId))
                    .collect(Collectors.toList());

            module.setName(moduleDto.getName());
            module.setUsers(users);
            module.setCur(0);

            return module;
        }).collect(Collectors.toSet());

        project.setModules(modules);

        Set<RiskDto> riskDtos = projectDto.getRiskDtos();

        Set<ProjectRiskMapping> projectRiskMappings = riskDtos.stream().map(riskDto -> {

            ProjectRiskMapping mapping = new ProjectRiskMapping();

            User user = userRepository.findByIdWithRoles(riskDto.getUserId());
            Risk risk = riskRepository.findById(riskDto.getRiskId()).orElse(null);

            mapping.setRisk(risk);
            mapping.setProject(project);
            mapping.setUser(user);
            mapping.setSort(riskDto.getSort());
            mapping.setStatus(riskDto.getStatus());

            return mapping;

        }).collect(Collectors.toSet());

        project.setRisks(projectRiskMappings);
        mappingRepository.saveAll(projectRiskMappings);
        projectRepository.save(project);

        return true;
    }

    @Override
    public ProjectResultDto get(Long projectId) {

        Project project = projectRepository.findByIdWithLazyProperties(projectId);
        ProjectResultDto resultDto = ProjectMapper.INSTANCE.projectToProjectResultDto(project);

        Set<Module> modules = projectRepository.findModules(project.getId());
        resultDto.setModules(modules);

        return resultDto;
    }

    @Override
    public Page<ProjectResultDto> page(int page, int size) {

        List<Project> projects = projectRepository.findAllWithLazyProperties();

        List<ProjectResultDto> dtos = projects.stream().map(project -> {

            ProjectResultDto dto = ProjectMapper.INSTANCE.projectToProjectResultDto(project);

            Set<Module> modules = projectRepository.findModules(project.getId());
            dto.setModules(modules);

            return dto;

        }).collect(Collectors.toList());

        return DataUtils.listToPage(dtos , page - 1 , size);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(Long projectId) throws JsonProcessingException {

        Project project = projectRepository.findByIdWithLazyProperties(projectId);

        int status = project.getStatus();

        if (2 == status) {
            throw new CustomException("项目已交付！");
        }

        if (0 == status) {
            project.setStatus(status + 1);
            projectRepository.save(project);

            return true;
        }

        ObjectMapper objectMapper = new ObjectMapper();

        String stage = project.getStages();
        List<String> stages = objectMapper.readValue(stage , new TypeReference<List<String>>() {});
        int stageNum = stages.size();

        if (stageNum == project.getCur()) {
            project.setStatus(status + 1);
            projectRepository.save(project);

            return true;
        }

        return false;
    }
}
